﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SimpleCADControl.GeoObjects;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Xml;
using System.IO;
using System.Drawing.Drawing2D;
using System.Reflection;
using System.Globalization;

namespace SimpleCADControl
{
    public partial class CADControl : UserControl
    {
        #region COM-Interfaces
        [DllImport("user32.dll", EntryPoint = "SendInput", SetLastError = true)]
        static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);

        [DllImport("user32.dll", EntryPoint = "GetMessageExtraInfo", SetLastError = true)]
        static extern IntPtr GetMessageExtraInfo();

        private enum InputType
        {
            INPUT_MOUSE = 0,
            INPUT_KEYBOARD = 1,
            INPUT_HARDWARE = 2,
        }

        [Flags()]
        private enum MOUSEEVENTF
        {
            MOVE = 0x0001,  // mouse move 
            LEFTDOWN = 0x0002,  // left button down
            LEFTUP = 0x0004,  // left button up
            RIGHTDOWN = 0x0008,  // right button down
            RIGHTUP = 0x0010,  // right button up
            MIDDLEDOWN = 0x0020,  // middle button down
            MIDDLEUP = 0x0040,  // middle button up
            XDOWN = 0x0080,  // x button down 
            XUP = 0x0100,  // x button down
            WHEEL = 0x0800,  // wheel button rolled
            VIRTUALDESK = 0x4000,  // map to entire virtual desktop
            ABSOLUTE = 0x8000,  // absolute move
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct MOUSEINPUT
        {
            public int dx;
            public int dy;
            public int mouseData;
            public MOUSEEVENTF dwFlags;
            public int time;
            public IntPtr dwExtraInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct INPUT
        {
            public InputType type;
            public MOUSEINPUT mi;
        }
        #endregion

        /// <summary>
        /// verschiedene Modi für das CADControl
        /// </summary>
        public enum CADEditMode { Move, Edit, View, Add, Cut, Measure }
        public event EventHandler<MeasureEventArgs> SaveMeasure;
        public event EventHandler<GeoObjectEventArgs> ObjectClicked;
        public event EventHandler<GeoObjectEventArgs> ObjectDeleted;
        public event EventHandler<EventArgs> Undone;
        public List<List<GeoObject>> undoList = new List<List<GeoObject>>();
        private bool mouseMove = false;

        private bool zoomChangedByTextBox = false;

        //Verschiebematrix von Bildkoordinaten in Picturebox - Koordinaten
        public Matrix2D TranslationScaleMatrix { get; private set; }
        private bool inCreationMode;
        //Liste von zu zeichnenden Objekten
        private List<GeoObject> geoObjects = new List<GeoObject>();

        private Vector2D measureStartTranslated;
        private Vector2D measureEndTranslated;
        private double measureDistance;
        private bool isMeasuring = false;
        private bool isCalibrating = false;
        private double calibrationFactor = 1;
        private double pxCount = 0;
        private Vector2D prevMousePoint;
        //Aktuell ausgewähltes Objekt, wichtig für Verschieben und Editieren
        private GeoObject selectedObject = null;
        public Color countColor = Color.Black;
        //private Vector2D selectedPoint = null;
        private int selectedPointIndex;
        private Vector2D lastMousePoint;
        //Wird beim MouseDown gesetzt, um eine grüne Linie beim Verschieben zu zeichnen
        private Vector2D mouseStartPoint;
        //Wird beim MouseMove gesetzt, um immer die aktuelle Mausposition zu haben
        private Vector2D currMouseCoords;

        private Vector2D startPoint;
        private Vector2D currPoint;
        private GeoObject aNewObject = null;

        public Dictionary<int, Pen> layerColorTable;

        public int TrackBarRadius
        {
            get
            {
                return trackBarRadius.Value;
            }
        }

        public struct PointColor
        {
            public Point point;
            public Color color;
        }
        public List<PointColor> manualCellCountPoints = new List<PointColor>();
        private int countRadius = 3;
        /// <summary>
        /// Konstruktor
        /// </summary>
        public CADControl()
        {
            InitializeComponent();
            selectedPointIndex = -1;
            PropertyGridVisible = true;
            pictureBox.ContextMenu = null;
            //pictureBox.DoubleClickRestore = false;
            TranslationScaleMatrix = Matrix2D.Identity;
            EditMode = CADEditMode.View;
            pictureBox.CurrentZoomChanged += new EventHandler(pictureBox_CurrentZoomChanged);
            pictureBox.ScrollPositionChanged += new EventHandler(pictureBox_ScrollPositionChanged);
            pictureBox.MouseWheel += new MouseEventHandler(pictureBox_MouseWheel);
            try
            {
                Bitmap bmp = new Bitmap("Cursor.bmp");
                bmp.MakeTransparent(Color.White);
                Cursor myCursor = CustomCursor.CreateCursor(bmp, 31, 31);
                pictureBox.Cursor = myCursor;
            }
            catch { }

            toolStripStatusLabelCoordinates.Text = "0 x 0";
            //toolStripTextBoxZoom.Text = ((int)pictureBox.CurrentZoom / 100).ToString();


            //Kamera freigeben
            if (VLib.Grabber.CountGrabberDevices() > 0)
            {
                //Kamera scheint vorhanden zu sein, Menupunkt freigeben beginnen:

                toolStripButtonLiveImage.Enabled = true;
            }


            LayerColorTable = new Dictionary<int, Pen>();

        }


        protected override void OnLoad(EventArgs e)
        {
            //Parameter laden
            try
            {
                String[] calibSettings = File.ReadAllText("calibration").Split(':');
                if (!double.TryParse(calibSettings[0], out calibrationFactor))
                {
                    calibrationFactor = 1;
                }
                toolStripStatusLabelCalibFactor.Text = calibrationFactor.ToString();
                toolStripTextBoxMeters.Text = calibSettings[1];

            }
            catch { }
            try
            {
                String[] colorLines = File.ReadAllLines("Layer_colors");
                String UseLayerColorString = colorLines[0];
                bool useLC;
                if (bool.TryParse(UseLayerColorString, out useLC))
                {
                    UseLayerColors = useLC;
                }
                foreach (String line in colorLines.Skip(1))
                {
                    String[] colorParams = line.Split(':');
                    Color c;
                    int argb;
                    int width;
                    int layerNumber;
                    if (!int.TryParse(colorParams[1], out argb))
                    {
                        c = Color.Black;
                    }
                    else
                    {
                        c = Color.FromArgb(argb);
                    }
                    if (!int.TryParse(colorParams[2], out width))
                    {
                        width = 1;
                    }
                    if (!int.TryParse(colorParams[0], out layerNumber))
                    {
                        break;
                    }
                    LayerColorTable.Add(layerNumber, new Pen(c, width));
                }
                UpdateLayersInContextMenus();
            }
            catch
            {
                //datei konnte nicht gelesen werden
            }
            base.OnLoad(e);
        }



        public void DeselectAllObjects()
        {
            foreach (var obj in GeoObjects)
            {
                obj.IsActive = false;
                obj.Flash = false;
            }
        }

        void pictureBox_MouseWheel(object sender, MouseEventArgs e)
        {
            UpdateTranslation();

            //if (EditMode == CADEditMode.Move)
            //{
            //    selectedObject.MoveMatrix.Matrix[0, 2] = e.Location.X - mouseStartPoint.X;
            //    selectedObject.MoveMatrix.Matrix[1, 2] = e.Location.Y - mouseStartPoint.Y;
            //    selectedObject.Move();
            ////    lastMousePoint = e.Location;
            //////    selectedObject.Move();
            ////    for (int i = 0; i < selectedObject.EditPoints.Count; i++)
            ////    {
            ////        selectedObject.EditPoints[i] *= TranslationScaleMatrix;
            ////    }
            ////    selectedObject.MovePoint = e.Location * TranslationScaleMatrix.Invert();
            //}
            if (EditMode == CADEditMode.Edit)
            {
                selectedObject.EditPoints[selectedPointIndex] = e.Location * TranslationScaleMatrix.Invert();
            }
            mouseStartPoint = e.Location;
            pictureBox.Invalidate(true);
        }


        /// <summary>
        /// Wird aufgerufen, wenn sich die Scrollposition ändert. Translationsmatrix wird angepasst!
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void pictureBox_ScrollPositionChanged(object sender, EventArgs e)
        {
            UpdateTranslation();
            pictureBox.Invalidate(true);
        }

        /// <summary>
        /// Aktualisiert die Verschiebung
        /// </summary>
        void UpdateTranslation()
        {
            TranslationScaleMatrix.Matrix[0, 2] = -pictureBox.HorizontalScroll.Value;
            TranslationScaleMatrix.Matrix[1, 2] = -pictureBox.VerticalScroll.Value;
        }


        void UpdateZoom()
        {
            TranslationScaleMatrix.Matrix[0, 0] = pictureBox.CurrentZoom;
            TranslationScaleMatrix.Matrix[1, 1] = pictureBox.CurrentZoom;
        }

        /// <summary>
        /// Wird aufgerufen, wenn sich der Zoom ändert. Translationsmatrix wird angepasst!
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void pictureBox_CurrentZoomChanged(object sender, EventArgs e)
        {
            UpdateZoom();
            UpdateTranslation();
            this.Invoke((MethodInvoker)delegate()
            {
                pictureBox.Invalidate(true);
            });
            if (!zoomChangedByTextBox)
            {
                this.Invoke((MethodInvoker)delegate()
                {
                    toolStripTextBoxZoom.Text = ((int)(pictureBox.CurrentZoom * 100)).ToString();
                });
            }
        }



        #region Parameters
        public Tpsc.Controls.PictureBoxEx PictureBox
        {
            get
            {
                return pictureBox;
            }
        }

        private CADEditMode editMode;
        public CADEditMode EditMode
        {
            get
            {
                return editMode;
            }
            set
            {
                this.Invalidate(true);
                editMode = value;
                toolStripStatusLabelEditMode.Text = EditMode.ToString();
                pictureBox.CanZoom = editMode == CADEditMode.View; //Zoomen nur erlauben, wenn nichts selektiert ist
                if (editMode == CADEditMode.View && selectedObject != null)
                {
                    selectedObject.IsMoving = false; //sonst wird grüne Linie zum Verschieben gezeichnet, wenn man View im Code gesetzt hat
                }
            }
        }
        public GeoObject SelectedObject
        {
            get
            {
                return selectedObject;
            }
        }
        public Object PropertyObject
        {
            set
            {
                propertyGrid.SelectedObject = value;
            }
        }

        public List<GeoObject> GeoObjects
        {
            get
            {
                return geoObjects;
            }
            private set
            {
                geoObjects = value;
            }
        }

        public void Add(GeoObject obj)
        {
            obj.Parent = this;
            GeoObjects.Add(obj);
        }

        public void Remove(GeoObject obj)
        {
            GeoObjects.Remove(obj);
        }
        private String imagePath = "";
        public Bitmap ImageBMP
        {
            get
            {
                return (Bitmap)pictureBox.Image;
            }
            set
            {
                pictureBox.Image = value;
                if(value!=null)
                    FitImgInPicBox();
            }
        }
        public String Image
        {
            get
            {
                return imagePath;
            }
            set
            {
                if (value != null && File.Exists(value))
                {
                    try
                    {
                        FileStream fs = new FileStream(value, FileMode.Open, FileAccess.Read);
                        pictureBox.Image = System.Drawing.Image.FromStream(fs);
                        fs.Close();
                        fs.Dispose();
                        GC.Collect();
                        imagePath = value;
                        FitImgInPicBox();
                    }
                    catch { }
                }
            }
        }
        [Category("Verschiedenes"),
        System.ComponentModel.DefaultValue("true")]
        public bool DrawLineBtnVisible
        {
            get
            {
                return toolStripButtonDrawLine.Visible;
            }
            set
            {
                toolStripButtonDrawLine.Visible = value;
            }
        }
        [Category("Verschiedenes"),
        System.ComponentModel.DefaultValue("true")]
        public bool DrawCircleBtnVisible
        {
            get
            {
                return toolStripButtonDrawCircle.Visible;
            }
            set
            {
                toolStripButtonDrawCircle.Visible = value;
            }
        }
        [Category("Verschiedenes"),
        System.ComponentModel.DefaultValue("true")]
        public bool DrawEllipseBtnVisible
        {
            get
            {
                return toolStripButtonDrawEllipse.Visible;
            }
            set
            {
                toolStripButtonDrawEllipse.Visible = value;
            }
        }
        [Category("Verschiedenes"),
        System.ComponentModel.DefaultValue("true")]
        public bool DrawPolylineBtnVisible
        {
            get
            {
                return toolStripButtonDrawPolyline.Visible;
            }
            set
            {
                toolStripButtonDrawPolyline.Visible = value;
            }
        }
        [Category("Verschiedenes"),
        System.ComponentModel.DefaultValue("true")]
        public bool DrawPolygonBtnVisible
        {
            get
            {
                return toolStripButtonDrawPolygon.Visible;
            }
            set
            {
                toolStripButtonDrawPolygon.Visible = value;
            }
        }



        /// <summary>
        /// Kalibrierfaktor
        /// </summary>
        public double CalibrationFactor
        {
            get
            {
                return calibrationFactor;
            }
        }

        /// <summary>
        /// Aktiviert die Click-And-Hold-Funktion
        /// </summary>
        [Category("Verschiedenes"),
        System.ComponentModel.DefaultValue("true")]
        public bool ClickAndHold { get; set; }

        private bool showCrossHair;
        /// <summary>
        /// Gibt an ob das Crosshair sichtbar ist
        /// </summary>
        [Category("Verschiedenes"),
        System.ComponentModel.DefaultValue("true")]
        public bool ShowCrossHair
        {
            get
            {
                return showCrossHair;
            }
            set
            {
                showCrossHair = value;
            }
        }


        /// <summary>
        /// Tabelle mit Farbinformationen für verschiedene Layer
        /// </summary>
        [Browsable(false)]
        public Dictionary<int, Pen> LayerColorTable
        {
            get
            {
                return layerColorTable;
            }
            set
            {
                layerColorTable = value;
            }
        }

        private bool useLayerColors = false;
        /// <summary>
        /// Gibt an, ob Layerfarben verwendet werden sollen
        /// </summary>
        [Category("Verschiedenes"),
        Description("Gibt an, ob Layerfarben verwendet werden sollen")]
        public bool UseLayerColors
        {
            get
            {
                return useLayerColors;
            }
            set
            {
                useLayerColors = value;
            }
        }

        //Kamera, falls vorhanden
        private VLib.Grabber grabber = null;


        /// <summary>
        /// Gibt den Zoom der Picturebox zurück
        /// </summary>
        [Category("Verschiedenes")]
        public double Zoom
        {
            get
            {
                return pictureBox.CurrentZoom;
            }
        }

        /// <summary>
        /// Infotext in der Statusbar
        /// </summary>
        [System.ComponentModel.Browsable(false)]
        public String InfoText
        {
            get
            {
                return toolStripStatusLabelInfos.Text;
            }
            set
            {
                toolStripStatusLabelInfos.Text = value;
            }
        }

        /// <summary>
        /// Gibt an, ob das PropertyGrid sichtbar ist
        /// </summary>
        [Category("Verschiedenes"),
        System.ComponentModel.DefaultValue("true")]
        public bool PropertyGridVisible
        {
            get
            {
                return propertyGrid.Visible;
            }
            set
            {
                propertyGrid.Visible = value;
                splitContainer1.Panel2Collapsed = !value;
            }
        }


        /// <summary>
        /// Gibt an, ob die Menuleiste sichtbar ist
        /// </summary>
        [Category("Verschiedenes"),
        System.ComponentModel.DefaultValue("true")]
        public bool MenuBarVisible
        {
            get
            {
                return toolStrip.Visible;
            }
            set
            {
                toolStrip.Visible = value;
            }
        }

        /// <summary>
        /// Gibt an, ob die Statusleiste sichtbar ist
        /// </summary>
        [Category("Verschiedenes"),
        System.ComponentModel.DefaultValue("true")]
        public bool StatusBarVisible
        {
            get
            {
                return statusStrip.Visible;
            }
            set
            {
                statusStrip.Visible = value;
            }
        }


        /// <summary>
        /// Aktuelle Mauskoordinaten
        /// </summary>
        [System.ComponentModel.Browsable(false)]
        public Vector2D CurrentMouseCoordinates
        {
            get
            {
                return currMouseCoords;
            }
        }

        /// <summary>
        /// Maus-Startposition für Verschiebungen usw.
        /// </summary>
        [System.ComponentModel.Browsable(false)]
        public Vector2D MouseStartPoint
        {
            get
            {
                return mouseStartPoint;
            }
        }
        #endregion


        /// <summary>
        /// Zeichenmethode
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pictureBox_Paint(object sender, PaintEventArgs e)
        {
            if (this.DesignMode)
            {
                base.OnPaint(e);
                return;
            }
            if (toolStripButtonHideObjects.Checked)
            {
                base.OnPaint(e);
                return;
            }
            try
            {
                //Für jedes Element Zeichenmethode aufrufen
                //Graphics bmpGraphics = Graphics.FromImage(pictureBox.Image);
                foreach (GeoObject element in GeoObjects)
                {
                    element.Draw(e.Graphics);
                }
                //bmpGraphics.Dispose();
            }
            catch { }
            try
            {
                if (showCrossHair)
                {
                    e.Graphics.DrawLine(Pens.Black, new Point(0, (int)currMouseCoords.Y), new Point(pictureBox.Width, (int)currMouseCoords.Y));
                    e.Graphics.DrawLine(Pens.Black, new Point((int)currMouseCoords.X, 0), new Point((int)currMouseCoords.X, pictureBox.Height));
                }
            }
            catch
            {
                //Beim neuen Start wurde Maus noch nicht bewegt, catch muss nicht weiter beachtet werden
            }
            try
            {
                if (EditMode == CADEditMode.Measure)
                {
                    Pen pen = new Pen(Color.Black, 1);
                    pen.StartCap = LineCap.ArrowAnchor;

                    pen.EndCap = LineCap.ArrowAnchor;
                    pen.DashPattern = new float[] { 5, 5 };
                    pen.DashStyle = DashStyle.Custom;

                    e.Graphics.DrawLine(pen, mouseStartPoint, isMeasuring || isCalibrating ? currMouseCoords : prevMousePoint);


                    if (isMeasuring || isCalibrating)
                    {
                        measureStartTranslated = mouseStartPoint * TranslationScaleMatrix.Invert();
                        measureEndTranslated = currMouseCoords * TranslationScaleMatrix.Invert();
                        pxCount = Math.Round((measureStartTranslated - measureEndTranslated).Sqrt(), 2);

                        measureDistance = pxCount / calibrationFactor; // Math.Round((pxCount * calibrationFactor), 2);
                    }


                    if (toolStripButtonCalibrate.Checked)
                    {
                        e.Graphics.DrawString("Calibration", new Font("Arial", 20), Brushes.Red, new PointF(0, 0));
                        e.Graphics.DrawString(pxCount.ToString() + " px", new Font("Arial", 8), Brushes.Black, isCalibrating ? currMouseCoords : mouseStartPoint);
                    }
                    else
                    {
                        //e.Graphics.DrawString(measureDistance.ToString() + " m", new Font("Arial", 8), Brushes.Black, isMeasuring ? currMouseCoords : mouseStartPoint);
                        SimpleCADControl.ExtensionClass.DoubleUnit dVal = measureDistance.ToDoubleUnit();
                        e.Graphics.DrawString(dVal.Value.ToString() + " " + dVal.Unit.ToString(), new Font("Arial", 8), Brushes.Black, isMeasuring ? currMouseCoords : mouseStartPoint);
                    }



                }
                if (toolStripButtonManualCellCount.Checked)
                {
                    foreach (var point in manualCellCountPoints)
                    {
                        Point p = point.point * TranslationScaleMatrix;
                        e.Graphics.FillEllipse(new SolidBrush(complementColorToolStripMenuItem.Checked ? point.color : countColor), new Rectangle(p.X - (int)((trackBarRadius.Value / 2) * pictureBox.CurrentZoom), p.Y - (int)( (trackBarRadius.Value / 2) * pictureBox.CurrentZoom), (int)(trackBarRadius.Value *pictureBox.CurrentZoom), (int)(trackBarRadius.Value * pictureBox.CurrentZoom)));
                        
                    }
                    e.Graphics.DrawString(manualCellCountPoints.Count.ToString(), new Font("Arial", 17), Brushes.Red, 0, 0);
                }
            }
            catch
            {
                //Beim neuen Start wurde Maus noch nicht bewegt, catch muss nicht weiter beachtet werden
            }
            
            base.OnPaint(e);

        }

        //override process

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            //Scrollbars mit den Pfeiltasten steuern. Ursprünglich in PictureBoxEx, aber die Translationen für die GeoObjects müssen
            //aktualisiert werden, daher jetzt hier implementiert

            switch (keyData)
            {
                case Keys.Down:
                    pictureBox.Scroll(Tpsc.Controls.ScrollDirection.Down, true);
                    UpdateTranslation();
                    Invalidate(true);
                    return true;
                case Keys.Up:
                    pictureBox.Scroll(Tpsc.Controls.ScrollDirection.Up, true);
                    UpdateTranslation();
                    Invalidate(true);
                    return true;
                case Keys.Left:
                    pictureBox.Scroll(Tpsc.Controls.ScrollDirection.Left, true);
                    UpdateTranslation();
                    Invalidate(true);
                    return true;
                case Keys.Right:
                    pictureBox.Scroll(Tpsc.Controls.ScrollDirection.Right, true);
                    UpdateTranslation();
                    Invalidate(true);
                    return true;

                //Maussteuerung mit dem Ziffernblock
                case Keys.NumPad4:
                    Cursor.Position = new Point(Cursor.Position.X - 1, Cursor.Position.Y);
                    break;
                case Keys.NumPad6:
                    Cursor.Position = new Point(Cursor.Position.X + 1, Cursor.Position.Y);
                    break;
                case Keys.NumPad8:
                    Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y - 1);
                    break;
                case Keys.NumPad2:
                    Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + 1);
                    break;
                case Keys.NumPad7:
                    Cursor.Position = new Point(Cursor.Position.X - 1, Cursor.Position.Y - 1);
                    break;
                case Keys.NumPad9:
                    Cursor.Position = new Point(Cursor.Position.X + 1, Cursor.Position.Y - 1);
                    break;
                case Keys.NumPad3:
                    Cursor.Position = new Point(Cursor.Position.X + 1, Cursor.Position.Y + 1);
                    break;
                case Keys.NumPad1:
                    Cursor.Position = new Point(Cursor.Position.X - 1, Cursor.Position.Y + 1);
                    break;
                case Keys.NumPad5:
                    SimulateMouseClick();
                    break;
                case Keys.Escape:

                    Matrix2D invertedMatrix = TranslationScaleMatrix.Invert();
                    Vector2D translatedMouseStartPoint = startPoint;// mouseStartPoint * invertedMatrix;
                    if (EditMode == CADEditMode.Edit)
                    {
                        selectedObject.EditPoints[selectedObject.CurrentPointToEditIndex] = startPoint;// mouseStartPoint* invertedMatrix;
                    }
                    else if (EditMode == CADEditMode.Move)
                    {
                        Vector2D currTranslatedMouseCoords = currPoint;// currMouseCoords* invertedMatrix;
                        selectedObject.MoveMatrix.Matrix[0, 2] = translatedMouseStartPoint.X - currTranslatedMouseCoords.X; //MoveMatrix berechnen
                        selectedObject.MoveMatrix.Matrix[1, 2] = translatedMouseStartPoint.Y - currTranslatedMouseCoords.Y;
                        selectedObject.Move();
                    }
                    selectedObject.CurrentPointToEditIndex = -1;
                    EditMode = CADEditMode.View;
                    break;

                default: break;
            }

            if (keyData == Keys.S)
            {
                SaveMeasure(this, new MeasureEventArgs(measureStartTranslated, measureEndTranslated, measureDistance, pxCount));
            }
            if (keyData == Keys.M)
            {
                toolStripButtonRuler.Checked = !toolStripButtonRuler.Checked;
            }
            if (keyData == Keys.Delete)
            {
                if (toolStripButtonManualCellCount.Checked)
                {
                    manualCellCountPoints.Clear();
                    toolStripButtonUndo.Enabled = false;
                    this.Invalidate(true);
                    return base.ProcessCmdKey(ref msg, keyData);
                }

                objektLöschenToolStripMenuItem_Click(this, new EventArgs());
                //Falls noch GeoObjects übrig nächstes selektieren:
                try
                {
                    if (GeoObjects.Count > 0)
                    {
                        DeselectAllObjects();
                        bool nextSelected = false;
                        foreach (var obj in GeoObjects)
                        {
                            if (Convert.ToInt32(obj.Label) == Convert.ToInt32(selectedObject.Label) + 1)
                            {
                                selectedObject = obj;
                                selectedObject.IsActive = true;
                                propertyGrid.SelectedObject = obj;
                                nextSelected = true;                               
                                break;
                            }
                        }
                        if (nextSelected == false)
                        {
                            foreach (var obj in GeoObjects)
                            {
                                if (Convert.ToInt32(obj.Label) == Convert.ToInt32(selectedObject.Label) - 1)
                                {
                                    selectedObject = obj;
                                    selectedObject.IsActive = true;
                                    propertyGrid.SelectedObject = obj;
                                    nextSelected = true;
                                    break;
                                }
                            }
                        }
                    }
                }
                catch { }
            }
            return base.ProcessCmdKey(ref msg, keyData);
        }


        /// <summary>
        /// Simuliert mit Hilfe von COM einen Mausklick
        /// </summary>
        /// <returns></returns>
        private static uint SimulateMouseClick()
        {
            INPUT input_down = new INPUT();
            input_down.type = InputType.INPUT_MOUSE;

            input_down.mi.dx = 0;
            input_down.mi.dy = 0;
            input_down.mi.mouseData = 0;
            input_down.mi.dwFlags = MOUSEEVENTF.LEFTDOWN;
            input_down.mi.time = 0;
            input_down.mi.dwExtraInfo = GetMessageExtraInfo();

            INPUT input_up = input_down;
            input_up.mi.dwFlags = MOUSEEVENTF.LEFTUP;

            INPUT[] input = { input_down, input_up };
            return SendInput(2, input, Marshal.SizeOf(input_down));
        }

        /// <summary>
        /// Methode wird aufgerufen, wenn in Control geklickt wird
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pictureBox_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Middle || Control.ModifierKeys == Keys.Alt)
            {
                mouseStartPoint = new Vector2D(e.X, e.Y);
                mouseMove = true;
                return;
            }

            if (toolStripButtonManualCellCount.Checked)
            {
                if (e.Button == System.Windows.Forms.MouseButtons.Right)
                {
                    trackBarRadius.Location = e.Location;

                    trackBarRadius.Visible = !trackBarRadius.Visible;
                    return;
                }
                trackBarRadius.Visible = false;
                Vector2D mp = e.Location * TranslationScaleMatrix.Invert();
                manualCellCountPoints.Add(new PointColor(){ point = mp, color = (new Bitmap(Image)).GetPixel((int)mp.X, (int) mp.Y).Complement() });
                toolStripButtonUndo.Enabled = manualCellCountPoints.Count > 0;
                return;
            }
            try
            {
                bool objectSelectedBefore = true; //Speichert ab, ob Objekt vor Methodenaufruf schon selektiert war
                prevMousePoint = mouseStartPoint;
                //Aktuelle Mausposition speichern...
                Vector2D mousePoint = new Vector2D(e.X, e.Y);
                mouseStartPoint = new Vector2D(e.X, e.Y);
                //...und in Picturebox - Koordinaten umrechnen
                mousePoint = mousePoint * TranslationScaleMatrix.Invert();
                lastMousePoint = new Vector2D(e.X, e.Y);
                if (toolStripButtonRuler.Checked)
                {
                    EditMode = CADEditMode.Measure;
                    isMeasuring = !isMeasuring;

                    return;
                }
                if (toolStripButtonCalibrate.Checked)
                {
                    EditMode = CADEditMode.Measure;
                    isCalibrating = !isCalibrating;
                    if (!isCalibrating)
                    {
                        double meters;
                        if (double.TryParse(toolStripTextBoxMeters.Text, NumberStyles.Float, CultureInfo.InvariantCulture, out meters))
                        {
                            calibrationFactor = pxCount / meters;
                            toolStripStatusLabelCalibFactor.Text = "calibration factor: " + calibrationFactor.ToString();
                            try
                            {
                                File.WriteAllText("calibration", calibrationFactor.ToString() + ":" + toolStripTextBoxMeters.Text);
                            }
                            catch
                            {
                                //datei konnte nicht geschrieben werden
                            }
                            //toolStripButtonCalibrate.Checked = false; //Kalibrierung automatisch abschalten...wird nicht benötigt und funktioniert nicht so
                            //pictureBox.Invalidate(true);

                        }
                    }
                    return;
                }
                if (EditMode == CADEditMode.Cut && selectedObject.EditPoints.Count <= 3)
                {
                    EditMode = CADEditMode.View;
                    return;
                }


                if (EditMode == CADEditMode.Cut && selectedObject.EditPoints.Count > 3)
                {
                    try
                    {
                        //Zu Beginn die aktuelle Geo-Object-Liste in die undoList speichern
                        //undoList.Add(geoObjects.Clone());
                        int i = 0;
                        
                        
                        foreach (var point in selectedObject.EditPoints)
                        {
                            //if (mousePoint.X >= point.X - 3f * Zoom &&
                            //    mousePoint.X <= point.X + 3f * Zoom &&
                            //    mousePoint.Y >= point.Y - 3f * Zoom &&
                            //    mousePoint.Y <= point.Y + 3f * Zoom)
                            //{
                            //Mit Zoom gabs Probleme, also ohne Zoom
                            if (mousePoint.X >= point.X - 3f &&
                               mousePoint.X <= point.X + 3f &&
                               mousePoint.Y >= point.Y - 3f &&
                               mousePoint.Y <= point.Y + 3f)
                            {
                                
                                if (selectedObject.EditPoints[selectedObject.CurrentPointToEditIndex].Equals(point))
                                {
                                    EditMode = CADEditMode.View;
                                    return;
                                }
                                pictureBox.CreateGraphics().DrawLine(Pens.Black, (Point)(selectedObject.EditPoints[selectedObject.CurrentPointToEditIndex] * TranslationScaleMatrix.Invert()), (Point)mousePoint);
                                Polygon p = new Polygon(selectedObject.EditPoints.GetRange(Math.Min(i, selectedObject.CurrentPointToEditIndex), Math.Max(i, selectedObject.CurrentPointToEditIndex) - Math.Min(i, selectedObject.CurrentPointToEditIndex) + 1).ToArray());
                                p.Parent = this;
                                p.Layer = selectedObject.Layer;
                                GeoObjects.Add(p);

                                Polygon p2 = (Polygon)selectedObject.Clone();
                                p2.EditPoints.RemoveRange(Math.Min(i, selectedObject.CurrentPointToEditIndex) + 1, Math.Max(i, selectedObject.CurrentPointToEditIndex) - Math.Min(i, selectedObject.CurrentPointToEditIndex) - 1);
                                GeoObjects.Add(p2);
                                GeoObjects.Remove(selectedObject);
                                selectedObject = null;
                                EditMode = CADEditMode.View;
                                return;
                            }
                            i++;
                        }
                    }
                    catch (System.Exception ex)
                    {
                        EditMode = CADEditMode.View;
                        MessageBox.Show("Fehler beim Schneiden! " + ex.Message);
                    }
                }

                //Konstruktionsmodus, u.a. zum Punkte zählen
                if (inCreationMode)
                {
                    selectedPointIndex++;
                    aNewObject.CurrentPointToEditIndex++;

                    if (aNewObject is Ellipse)
                    {
                        if (selectedPointIndex == 1)
                        {
                            //Punkt für Höhe der Ellipse setzen, da sonst der Punkt zum Verschieben der Höhe nicht unter der Maus liegt. X-Koordinate vom MovePoint verwenden!
                            selectedObject.EditPoints[1] = new Vector2D(selectedObject.MovePoint.X, mousePoint.Y);
                        }
                        if (selectedPointIndex == 2)
                        {
                            inCreationMode = false;
                            selectedPointIndex = -1;
                            EditMode = CADEditMode.View;
                        }
                    }

                    //Polyline und Polygon können auf gleiche Weise konstruiert werden
                    if (aNewObject is PolyLine || aNewObject is Polygon)
                    {
                        if ((e.Button != System.Windows.Forms.MouseButtons.Right) || (aNewObject.EditPoints.Count < 3))
                        {

                            Vector2D vec = new Vector2D(e.X, e.Y);
                            (aNewObject as GeoObject).EditPoints.Add(vec * TranslationScaleMatrix.Invert());
                        }
                        else
                        {
                            inCreationMode = false;
                            selectedPointIndex = -1;
                            aNewObject.CurrentPointToEditIndex = -1;
                            for (int i = 0; i < GeoObjects.Count; i++)
                            {
                                GeoObjects[i].IsActive = false;
                            }
                            aNewObject.IsActive = true;
                            EditMode = CADEditMode.View;
                        }

                    }

                    //siehe Bedingung darüber!
                    //if (aNewObject is Polygon)
                    //{
                    //    if (e.Button != System.Windows.Forms.MouseButtons.Right)
                    //    {

                    //        Vector2D vec = new Vector2D(e.X, e.Y);
                    //        (aNewObject as Polygon).EditPoints.Add(vec * TranslationScaleMatrix.Invert());
                    //    }
                    //    else
                    //    {
                    //        inCreationMode = false;
                    //        selectedPointIndex = -1;
                    //        aNewObject.CurrentPointToEditIndex = -1;
                    //        EditMode = CADEditMode.View;
                    //    }
                    //    //EditMode = CADEditMode.;
                    //}


                    return;
                }

                //Modus zum Hinzufügen von Objekten
                if (EditMode == CADEditMode.Add)
                {
                    //Zu Beginn die aktuelle Geo-Object-Liste in die undoList speichern
                    
                    //Linie

                    aNewObject.Parent = this;
                    DeselectAllObjects();
                    aNewObject.IsActive = true;
                    if (aNewObject is Line)
                    {
                        (aNewObject as Line).EditPoints = new List<Vector2D>();
                        Vector2D vec = new Vector2D(e.X, e.Y);
                        (aNewObject as Line).EditPoints.Add(vec * TranslationScaleMatrix.Invert());

                        (aNewObject as Line).EditPoints.Add(vec * TranslationScaleMatrix.Invert());
                        GeoObjects.Add(aNewObject);
                        selectedPointIndex = 1; //Move - Modus umgehen
                        aNewObject.CurrentPointToEditIndex = 1; //Punkt für Radius grau zeichnen
                        EditMode = CADEditMode.View;

                        pictureBox.Invalidate(true);
                    }

                    //Kreis
                    if (aNewObject is Circle)
                    {
                        (aNewObject as Circle).EditPoints = new List<Vector2D>();
                        Vector2D vec = new Vector2D(e.X, e.Y);
                        (aNewObject as Circle).MovePoint = vec * TranslationScaleMatrix.Invert();
                        (aNewObject as Circle).EditPoints.Add(vec * TranslationScaleMatrix.Invert());
                        selectedPointIndex = 0;
                        GeoObjects.Add(aNewObject);

                        aNewObject.CurrentPointToEditIndex = 0;
                        EditMode = CADEditMode.View; //Wichtig, da sonst selectedObject auf -1 gesetzt wird, s. weiter unten

                        pictureBox.Invalidate(true);
                    }

                    if (aNewObject is Ellipse)
                    {
                        (aNewObject as Ellipse).EditPoints = new List<Vector2D>();
                        Vector2D vec = new Vector2D(e.X, e.Y);
                        (aNewObject as Ellipse).MovePoint = vec * TranslationScaleMatrix.Invert();
                        (aNewObject as Ellipse).EditPoints.Add(vec * TranslationScaleMatrix.Invert());
                        (aNewObject as Ellipse).EditPoints.Add(vec * TranslationScaleMatrix.Invert());
                        inCreationMode = true;
                        GeoObjects.Add(aNewObject);
                        selectedObject = aNewObject;
                        selectedPointIndex = 0; //Move - Modus umgehen
                        aNewObject.CurrentPointToEditIndex = 0; //Punkt für Radius grau zeichnen
                        EditMode = CADEditMode.View; //Wichtig, da sonst selectedObject auf -1 gesetzt wird, s. weiter unten
                        //EditMode = CADEditMode.Edit;
                        pictureBox.Invalidate(true);

                    }

                    if (aNewObject is PolyLine || aNewObject is Polygon)
                    {
                        (aNewObject as GeoObject).EditPoints = new List<Vector2D>();
                        (aNewObject as GeoObject).MovePoint = new Vector2D(0, 0);
                        Vector2D vec = new Vector2D(e.X, e.Y);
                        (aNewObject as GeoObject).EditPoints.Add(vec * TranslationScaleMatrix.Invert());
                        (aNewObject as GeoObject).EditPoints.Add(vec * TranslationScaleMatrix.Invert());
                        inCreationMode = true;
                        GeoObjects.Add(aNewObject);
                        selectedObject = aNewObject;
                        selectedPointIndex = 1;
                        aNewObject.CurrentPointToEditIndex = 1;


                        pictureBox.Invalidate(true);
                        EditMode = CADEditMode.Edit; //Kann auf Edit bleiben, da return in nächster Zeile
                        return;
                    }

                    //if (aNewObject is Polygon)
                    //{
                    //    (aNewObject as Polygon).EditPoints = new List<Vector2D>();
                    //    (aNewObject as Polygon).MovePoint = new Vector2D(0, 0);
                    //    Vector2D vec = new Vector2D(e.X, e.Y);
                    //    (aNewObject as Polygon).EditPoints.Add(vec * TranslationScaleMatrix.Invert());
                    //    (aNewObject as Polygon).EditPoints.Add(vec * TranslationScaleMatrix.Invert());
                    //    inCreationMode = true;
                    //    GeoObjects.Add(aNewObject);
                    //    aNewObject.Parent = this;
                    //    selectedObject = aNewObject;
                    //    selectedPointIndex = 1;
                    //    aNewObject.CurrentPointToEditIndex = 1;


                    //    pictureBox.Invalidate(true);
                    //    EditMode = CADEditMode.Edit;
                    //    return;
                    //}
                }

                if (EditMode != CADEditMode.View)
                {
                    if (selectedObject != null)
                    {
                        selectedObject.IsMoving = false;
                        selectedPointIndex = -1;
                        selectedObject.CurrentPointToEditIndex = -1;

                    }
                    EditMode = CADEditMode.View;
                    return;
                }
                selectedObject = null;
                foreach (var obj in GeoObjects)
                {
                    //Prüfen, ob Objekt selektiert wurde
                    if (HitTest(obj, mousePoint))
                    {

                        selectedObject = obj;
                        if (obj.IsActive == false)
                        {
                            objectSelectedBefore = true; //TODO: eigentlich false, aber dann lassen sich Zellkerne nicht mehr selektieren...
                            DeselectAllObjects();
                            obj.IsActive = true;

                            EditMode = CADEditMode.View;
                            try
                            {
                                ObjectClicked(sender, new GeoObjectEventArgs { Obj = obj });
                            }
                            catch { }
                        }
                        else
                        {
                            objectSelectedBefore = true;
                        }

                        //Für Kontextmenu in Zelle: Stört beim Selektieren von Punkten, also ausblenden
                        //else
                        //{
                        //    if (e.Button == System.Windows.Forms.MouseButtons.Right)
                        //    {
                        //        //ContextMenu Öffnen
                        //        contextMenuStripMovePoint.Show(pictureBox, e.Location);
                        //        EditMode = CADEditMode.View;
                        //        selectedPointIndex = -1;

                        //        break;
                        //    }
                        //}

                    }
                    //Prüfen, ob Punkt zum Bewegen des Objekts angeklickt wurde
                    //if (mousePoint.X >= obj.MovePoint.X - 3f * Zoom &&
                    //    mousePoint.X <= obj.MovePoint.X + 3f * Zoom &&
                    //    mousePoint.Y >= obj.MovePoint.Y - 3f * Zoom &&
                    //    mousePoint.Y <= obj.MovePoint.Y + 3f * Zoom && selectedPointIndex < 0)
                    //{
                    //Mit Zoom gabs Probleme, also ohne zoom:
                    if (mousePoint.X >= obj.MovePoint.X - 3f &&
                       mousePoint.X <= obj.MovePoint.X + 3f &&
                       mousePoint.Y >= obj.MovePoint.Y - 3f &&
                       mousePoint.Y <= obj.MovePoint.Y + 3f && selectedPointIndex < 0)
                    {
                        selectedObject = obj;
                        startPoint = obj.MovePoint;
                        if (obj.IsActive == false || objectSelectedBefore == false)
                        {
                            DeselectAllObjects();
                            obj.IsActive = true;

                            try
                            {
                                ObjectClicked(sender, new GeoObjectEventArgs { Obj = selectedObject });
                            }
                            catch { }
                            EditMode = CADEditMode.View;
                            return;
                        }
                        obj.IsMoving = true;
                        if ((selectedObject.IsActive == true) && (e.Button == System.Windows.Forms.MouseButtons.Left))
                        {
                            //Zu Beginn die aktuelle Geo-Object-Liste in die undoList speichern
                            //undoList.Add(geoObjects.Clone());
                        }
                        //propertyGrid.SelectedObject = selectedObject;
                        //EditMode ändern und Schleife abbrechen
                        EditMode = CADEditMode.Move;
                        //lastMousePoint = new Vector2D(e.X, e.Y);
                        Debug.WriteLine("Hit");
                        break;
                    }

                    else
                    {
                        //Prüfen, ob Punkt zum Editieren des Objekts angeklickt wurde
                        foreach (var point in obj.EditPoints)
                        {
                            //Mit Zoom Funktioniert anklicken nicht richtig
                            //    if (mousePoint.X >= point.X - 3f * Zoom &&
                            //mousePoint.X <= point.X + 3f * Zoom &&
                            //mousePoint.Y >= point.Y - 3f * Zoom &&
                            //mousePoint.Y <= point.Y + 3f * Zoom)
                            //    {

                            if (mousePoint.X >= point.X - 3f &&
                            mousePoint.X <= point.X + 3f &&
                            mousePoint.Y >= point.Y - 3f &&
                            mousePoint.Y <= point.Y + 3f)
                            {
                                selectedObject = obj;
                                startPoint = point;
                                if (obj.IsActive == false || objectSelectedBefore == false)
                                {


                                    DeselectAllObjects();
                                    obj.IsActive = true;

                                    try
                                    {
                                        ObjectClicked(sender, new GeoObjectEventArgs { Obj = obj });
                                    }
                                    catch { }
                                    EditMode = CADEditMode.View;
                                    return;
                                }
                                //obj.IsMoving = true;

                                if ((selectedObject.IsActive == true) && (e.Button == System.Windows.Forms.MouseButtons.Left))
                                {
                                    //Zu Beginn die aktuelle Geo-Object-Liste in die undoList speichern
                                    //undoList.Add(geoObjects.Clone());
                                }
                                //propertyGrid.SelectedObject = selectedObject;
                                propertyGrid.PropertyTabs.Clear(PropertyTabScope.Document);
                                //selectedPoint = point;
                                selectedPointIndex = obj.EditPoints.IndexOf(point);
                                obj.CurrentPointToEditIndex = selectedPointIndex;

                                if (e.Button == System.Windows.Forms.MouseButtons.Right)
                                {
                                    //ContextMenu Öffnen
                                    selectedObject.OpenContextMenu(e.Location);
                                    EditMode = CADEditMode.View;
                                    selectedPointIndex = -1;

                                    //break;
                                    return;
                                }

                                //EditMode ändern und Schleife abbrechen
                                EditMode = CADEditMode.Edit;
                                //lastMousePoint = new Vector2D(e.X, e.Y);
                                Debug.WriteLine("Hit");



                                break;
                            }
                            else
                            {
                                EditMode = CADEditMode.View;
                            }
                        }
                        if (EditMode == CADEditMode.Edit) break;
                        //EditMode = CADEditMode.View;

                    }

                }

                if (selectedObject == null)
                {
                    DeselectAllObjects();
                    selectedObject = null;
                    selectedPointIndex = -1;
                    propertyGrid.SelectedObject = null;
                }

                if (e.Button == System.Windows.Forms.MouseButtons.Right)
                {
                    if (EditMode == CADEditMode.Move)
                    {
                        contextMenuStripMovePoint.Show(pictureBox, e.Location);
                    }

                    // Ich weiß nicht wo dieser Else - Teil herkommt und er sorgt dafür, dass das Programm abstürzt, aber irgendeinen Sinn hat er bestimmt mal gehabt :)
                    //else
                    //{
                    //    selectedPointIndex = -1;
                    //EditMode = CADEditMode.View;
                    //    selectedObject.CurrentPointToEditIndex = -1;
                    //}
                }
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("Fehler in MouseDown-Event " + ex.Message);
            }
        }




        /// <summary>
        /// Methode zum Testen, ob ein Polygon angeklickt wurde.
        /// </summary>
        /// <param name="obj">GeoObject, auf das getestet werden soll</param>
        /// <param name="p">Punkt, der angeklickt wurde</param>
        /// <returns>Bool</returns>
        public bool HitTest(GeoObject obj, Point p)
        {
            bool isHit = false;

            //Algorithmus für Bounding - Box
            //foreach(Vector2D vector in obj.EditPoints)
            //{
            //    //nach Links prüfen
            //    if (vector.X < p.X)
            //    {
            //        foreach (Vector2D vector2 in obj.EditPoints)
            //        {
            //            //nach rechts prüfen
            //            if (vector2.X > p.X)
            //            {
            //                foreach (Vector2D vector3 in obj.EditPoints)
            //                {
            //                    //nach Oben prüfen
            //                    if (vector3.Y < p.Y)
            //                    {
            //                        foreach (Vector2D vector4 in obj.EditPoints)
            //                        {
            //                            //nach unten prüfen
            //                            if (vector4.Y > p.Y)
            //                            {
            //                                isHit = true;
            //                                break;
            //                            }
            //                        }
            //                        break;
            //                    }
            //                }
            //                break;
            //            }
            //        }
            //        break;
            //    }
            //}

            //Algorithmus nach W. Randolph Franklin (PNPOLY)

            int nvert = obj.EditPoints.Count;
            double[] vertx = obj.EditPoints.Select(s => s.X).ToArray<double>();
            double[] verty = obj.EditPoints.Select(s => s.Y).ToArray<double>();
            double testx = p.X;
            double testy = p.Y;
            for (int i = 0, j = nvert - 1; i < nvert; j = i++)
            {
                if (((verty[i] > testy) != (verty[j] > testy)) &&
                 (testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i]))
                    isHit = !isHit;
            }


            return isHit;
        }


        /// <summary>
        /// Wird aufgerufen, wenn Maus über das Control bewegt wird
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void pictureBox_MouseMove(object sender, MouseEventArgs e)
        {
            try
            {
                this.Invalidate(true);
                if (mouseMove)
                {
                    int deltaX = (int)(mouseStartPoint.X - e.X);
                    int deltaY = (int)(mouseStartPoint.Y - e.Y);
                    pictureBox.AutoScrollPosition = new Point(
                        deltaX - pictureBox.AutoScrollPosition.X,
                        deltaY - pictureBox.AutoScrollPosition.Y);

                    mouseStartPoint = new Vector2D(e.X, e.Y);
                    UpdateTranslation();
                }

                //EditMode Move: Setzt voraus, dass Vorher Maustaste geklickt wurde->Siehe pictureBox_MouseDown
                currMouseCoords = new Vector2D(e.X, e.Y); //Aktuelle Mausposition in Vektor
                currPoint = selectedObject.MovePoint;
                Vector2D picCoords = currMouseCoords * TranslationScaleMatrix.Invert();

                //Wenn kein Fadenkreuz eingezeichnet werden soll, ist ein Invalidate überflüssig und bremst das System aus.
                if (showCrossHair)
                {
                    pictureBox.Invalidate(true);
                }
                toolStripStatusLabelCoordinates.Text = ((int)picCoords.X).ToString() + " x " + ((int)picCoords.Y).ToString();

                if (EditMode == CADEditMode.Move)
                {
                    if (!selectedObject.IsActive)
                    { return; } //Nicht aktive Objekte können nicht bearbeitet werden


                    lastMousePoint = lastMousePoint * TranslationScaleMatrix.Invert(); // "

                    selectedObject.MoveMatrix.Matrix[0, 2] = picCoords.X - lastMousePoint.X; //MoveMatrix berechnen
                    selectedObject.MoveMatrix.Matrix[1, 2] = picCoords.Y - lastMousePoint.Y;

                    lastMousePoint.X = e.X;
                    lastMousePoint.Y = e.Y;

                    selectedObject.Move();
                    
                        this.Invalidate(true);
                    

                }


                if (EditMode == CADEditMode.Edit)
                {

                    if (!selectedObject.IsActive)
                    { return; } //Nicht aktive Objekte können nicht bearbeitet werden

                    lastMousePoint = lastMousePoint * TranslationScaleMatrix.Invert(); // "

                    selectedObject.MoveMatrix.Matrix[0, 2] = picCoords.X - lastMousePoint.X; //MoveMatrix berechnen
                    selectedObject.MoveMatrix.Matrix[1, 2] = picCoords.Y - lastMousePoint.Y;

                    lastMousePoint.X = e.X;
                    lastMousePoint.Y = e.Y;

                    selectedObject.Edit(selectedPointIndex);
                    this.Invalidate(true);
                    
                }
            }
            catch { }

        }


        /// <summary>
        /// Wird ausgelöst, wenn Mausbutton losgelassen wird
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pictureBox_MouseUp(object sender, MouseEventArgs e)
        {
            mouseMove = false;
            if (!ClickAndHold)
            {
                if (selectedObject != null)
                {
                    selectedObject.IsMoving = false;
                    selectedObject.CurrentPointToEditIndex = -1;
                }
                EditMode = CADEditMode.View;

            }
            //Toolstrips wieder zurücksetzen:
            UncheckAllButtons();
        }



        private void objektLöschenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            undoList.Add(new List<GeoObject>(GeoObjects));
            try
            {
                ObjectDeleted(this, new GeoObjectEventArgs { Obj = selectedObject });
            }
            catch { }
            
            toolStripButtonUndo.Enabled = undoList.Count > 0;
            if(selectedObject.GetType()==typeof(GeoObjects.MultiPolygon))
            {
                foreach( var innerObject in (selectedObject as GeoObjects.MultiPolygon).Polygons)
                {
                    if(GeoObjects.Contains(innerObject))
                    {
                        GeoObjects.Remove(innerObject);
                    }
                }
            }
            GeoObjects.Remove(selectedObject);
            propertyGrid.SelectedObject = null;
            EditMode = CADEditMode.View;
            this.Invalidate(true);
        }

        private void objektClonenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GeoObject obj = selectedObject.Clone();
            GeoObjects.Add(obj);
            EditMode = CADEditMode.Move;
            this.Invalidate(true);
        }

        private void propertyGrid_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
        {
            this.Invalidate(true);
        }

        private void UncheckAllButtons()
        {
            toolStripButtonDrawLine.Checked = false;
            toolStripButtonDrawCircle.Checked = false;
            toolStripButtonDrawEllipse.Checked = false;
            toolStripButtonDrawPolyline.Checked = false;
            toolStripButtonDrawPolygon.Checked = false;
        }

        private void toolStripButtonDrawLine_Click(object sender, EventArgs e)
        {
            if (toolStripButtonDrawLine.Checked)
            {
                EditMode = CADEditMode.View;
                toolStripButtonDrawLine.Checked = false;
            }
            else
            {
                UncheckAllButtons();
                EditMode = CADEditMode.Add;
                toolStripButtonDrawLine.Checked = true;
                aNewObject = new Line();
            }
        }

        private void toolStripButtonDrawCircle_Click(object sender, EventArgs e)
        {
            if (toolStripButtonDrawCircle.Checked)
            {
                EditMode = CADEditMode.View;
                toolStripButtonDrawCircle.Checked = false;
            }
            else
            {
                UncheckAllButtons();
                EditMode = CADEditMode.Add;
                toolStripButtonDrawCircle.Checked = true;
                aNewObject = new Circle();
            }
        }

        private void toolStripButtonDrawEllipse_Click(object sender, EventArgs e)
        {
            if (toolStripButtonDrawEllipse.Checked)
            {
                EditMode = CADEditMode.View;
                toolStripButtonDrawEllipse.Checked = false;
            }
            else
            {
                UncheckAllButtons();
                EditMode = CADEditMode.Add;
                toolStripButtonDrawEllipse.Checked = true;
                aNewObject = new Ellipse();
            }
        }

        private void toolStripButtonDrawPolyline_Click(object sender, EventArgs e)
        {
            if (toolStripButtonDrawPolyline.Checked)
            {
                EditMode = CADEditMode.View;
                toolStripButtonDrawPolyline.Checked = false;
            }
            else
            {
                UncheckAllButtons();
                EditMode = CADEditMode.Add;
                toolStripButtonDrawPolyline.Checked = true;
                aNewObject = new PolyLine();
            }
        }

        private void toolStripButtonDrawPolygon_Click(object sender, EventArgs e)
        {
            if (toolStripButtonDrawPolygon.Checked)
            {
                EditMode = CADEditMode.View;
                toolStripButtonDrawPolygon.Checked = false;
            }
            else
            {
                UncheckAllButtons();
                EditMode = CADEditMode.Add;
                toolStripButtonDrawPolygon.Checked = true;
                aNewObject = new Polygon();
            }
        }




        private void toolStripTextBoxZoom_TextChanged(object sender, EventArgs e)
        {
            toolStripTextBoxZoom.BackColor = Color.White;
            zoomChangedByTextBox = true;
            //pictureBox.CurrentZoom = (float)(int.Parse(toolStripTextBoxZoom.Text) / 100.0f);
            
            int zoom;
            if (int.TryParse(toolStripTextBoxZoom.Text, out zoom) && zoom > 0)
            {

                pictureBox.CurrentZoom = (float)zoom / 100.0f;
            }
            else
            {
                toolStripTextBoxZoom.BackColor = Color.Red;
            }
            zoomChangedByTextBox = false;
        }

        private void toolStripStatusLabelInfos_DoubleClick(object sender, EventArgs e)
        {
            toolStripStatusLabelInfos.Text = "";
        }

       
        public void Save(String fileName)
        {
            XmlDocument newDocument = new XmlDocument();
            XmlNode rootNode = newDocument.CreateElement("Project");
            XmlNode objectsNode = newDocument.CreateElement("Objects");

            foreach (var obj in GeoObjects)
            {
                XmlNode newObjectNode = CreateObjectNode(obj, newDocument);
                if (obj.GetType() == typeof(MultiPolygon)) //Für Multipoligon Polygonliste abspeichern
                {
                    XmlNode polygonsNode = newDocument.CreateElement("Polygons");
                    foreach(Polygon p in (obj as MultiPolygon).Polygons)
                    {
                        polygonsNode.AppendChild(CreateObjectNode(p, newDocument));
                    }
                    newObjectNode.AppendChild(polygonsNode);
                }

                objectsNode.AppendChild(newObjectNode);              
                
                
            }
            rootNode.AppendChild(objectsNode);

            XmlNode bgImageNode = newDocument.CreateElement("BGImage");
            XmlAttribute bgImagePathAttr = newDocument.CreateAttribute("Path");
            bgImagePathAttr.Value = Image;
            bgImageNode.Attributes.Append(bgImagePathAttr);
            rootNode.AppendChild(bgImageNode);

            newDocument.AppendChild(rootNode);
            newDocument.Save(fileName);

        }


        private XmlNode CreateObjectNode(GeoObject obj, XmlDocument newDocument)
        {
                XmlNode newObjectNode = null; //newDocument.CreateElement("");
                if (obj.GetType() == typeof(Line))
                {
                    //Typ Linie
                    newObjectNode = newDocument.CreateElement("Line");

                }
                else if (obj.GetType() == typeof(PolyLine))
                {
                    //Typ PolyLine
                    newObjectNode = newDocument.CreateElement("PolyLine");

                }
                else if (obj.GetType() == typeof(Polygon))
                {
                    //Typ Polygon
                    newObjectNode = newDocument.CreateElement("Polygon");

                }
                else if (obj.GetType() == typeof(Ellipse))
                {
                    //Typ Ellipse
                    newObjectNode = newDocument.CreateElement("Ellipse");

                }
                else if (obj.GetType() == typeof(Circle))
                {
                    //Typ Circle
                    newObjectNode = newDocument.CreateElement("Circle");

                }
            else if (obj.GetType() == typeof(MultiPolygon))
            {
                newObjectNode = newDocument.CreateElement("MultiPolygon");
            }

                else
                {
                    //Typ Object
                    newObjectNode = newDocument.CreateElement("Object");

                }

                XmlNode vectorNode = newDocument.CreateElement("Vectors");
                foreach (Vector2D vector in obj.EditPoints)
                {
                    XmlNode vec = newDocument.CreateElement("Vector");
                    XmlAttribute xAttrib = newDocument.CreateAttribute("X");
                    xAttrib.Value = vector.X.ToString();
                    XmlAttribute yAttrib = newDocument.CreateAttribute("Y");
                    yAttrib.Value = vector.Y.ToString();
                    vec.Attributes.Append(xAttrib);
                    vec.Attributes.Append(yAttrib);
                    vectorNode.AppendChild(vec);
                }
                newObjectNode.AppendChild(vectorNode);
                XmlNode movePointNode = newDocument.CreateElement("MovePoint");
                XmlAttribute mvXAttrib = newDocument.CreateAttribute("X");
                mvXAttrib.Value = obj.MovePoint.X.ToString();
                XmlAttribute mvYAttrib = newDocument.CreateAttribute("Y");
                mvYAttrib.Value = obj.MovePoint.Y.ToString();
                movePointNode.Attributes.Append(mvXAttrib);
                movePointNode.Attributes.Append(mvYAttrib);
                newObjectNode.AppendChild(movePointNode);

                XmlNode penNode = newDocument.CreateElement("Pen");
                XmlAttribute penColorAttr = newDocument.CreateAttribute("Color");
                penColorAttr.Value = obj.DrawingPen.Color.ToArgb().ToString();
                XmlAttribute penWidthAttr = newDocument.CreateAttribute("Stroke");
                penWidthAttr.Value = obj.DrawingPen.Width.ToString();
                penNode.Attributes.Append(penColorAttr);
                penNode.Attributes.Append(penWidthAttr);
                newObjectNode.AppendChild(penNode);

 
            XmlAttribute labelAttr = newDocument.CreateAttribute("Label");
            labelAttr.Value = obj.Label;
            XmlAttribute layerAttr = newDocument.CreateAttribute("Layer");
            layerAttr.Value = obj.Layer.ToString();
            XmlAttribute infoAttr = newDocument.CreateAttribute("Info");
            infoAttr.Value = obj.Info;
            XmlAttribute statusAttr = newDocument.CreateAttribute("Status");
            statusAttr.Value = obj.Status;
            newObjectNode.Attributes.Append(labelAttr);
            newObjectNode.Attributes.Append(layerAttr);
            newObjectNode.Attributes.Append(infoAttr);
            newObjectNode.Attributes.Append(statusAttr);

            return newObjectNode;
        }

        GeoObject CreateObjectFromObjectNode(XmlNode objNode, XmlDocument newDocument)
        {
            GeoObject newObject = null;
                if (objNode.Name == "Line")
                {
                    newObject = new Line();
                }
                else if (objNode.Name == "PolyLine")
                {
                    newObject = new PolyLine();
                }
                else if (objNode.Name == "Polygon")
                {
                    newObject = new Polygon();
                }
                else if (objNode.Name == "Ellipse")
                {
                    newObject = new Ellipse();
                }
                else if (objNode.Name == "Circle")
                {
                    newObject = new Circle();
                }
                else if (objNode.Name == "MultiPolygon")
                {
                    XmlNode polygonsNode = objNode.SelectSingleNode("Polygons");
                    Polygon[] polygons = new Polygon[polygonsNode.ChildNodes.Count];
                    int i = 0;
                    foreach (XmlNode polygonNode in polygonsNode.ChildNodes)
                    {
                        polygons[i++] = (Polygon) CreateObjectFromObjectNode(polygonNode, newDocument);
                    }
                    newObject = new MultiPolygon(polygons);
                }
                else
                {
                    return null;
                }

                //EditPoints laden
                XmlNodeList editPointNodes = objNode.SelectSingleNode("Vectors").ChildNodes;
                List<Vector2D> newVectorList = new List<Vector2D>();
                foreach (XmlNode newVectorNode in editPointNodes)
                {
                    double x, y;
                    if (double.TryParse(newVectorNode.Attributes["X"].Value, out x) &&
                        double.TryParse(newVectorNode.Attributes["Y"].Value, out y))
                    {
                        Vector2D newVector = new Vector2D(x, y);
                        newVectorList.Add(newVector);
                    }
                }
                newObject.EditPoints = newVectorList;


                //MovePoint laden
                XmlNode movePointNode = objNode.SelectSingleNode("MovePoint");

                double mvX, mvY;
                if (double.TryParse(movePointNode.Attributes["X"].Value, out mvX) &&
                    double.TryParse(movePointNode.Attributes["Y"].Value, out mvY))
                {
                    Vector2D movePointVector = new Vector2D(mvX, mvY);
                    newObject.MovePoint = movePointVector;
                }

                //Pen laden
                XmlNode penNode = objNode.SelectSingleNode("Pen");
                float penWidth;
                int argbColor;
                Pen newPen = new Pen(Color.Black, 1);
                if (float.TryParse(penNode.Attributes["Stroke"].Value, out penWidth) &&
                    int.TryParse(penNode.Attributes["Color"].Value, out argbColor))
                {
                    newPen.Color = Color.FromArgb(argbColor);
                    newPen.Width = penWidth;
                }
                newObject.DrawingPen = newPen;

                newObject.Label = objNode.Attributes["Label"].Value;
                int layerNumber = 0;
                layerNumber = int.Parse(objNode.Attributes["Layer"].Value);
                newObject.Layer = layerNumber;
                newObject.Info = objNode.Attributes["Info"].Value;
                newObject.Status = objNode.Attributes["Status"].Value;


                return newObject;
               
        }

        public void SaveAsBitmap(String fileName)
        {
            bool showCross = ShowCrossHair;
            ShowCrossHair = false;
            pictureBox.Invalidate();
            Size scrollbarSize = pictureBox.Size - pictureBox.ClientSize;
            int width = pictureBox.Width - scrollbarSize.Width;
            int height = pictureBox.Height - scrollbarSize.Height;
            if (width > pictureBox.Image.Width)
                width = pictureBox.Image.Width;
            if (height > pictureBox.Image.Height)
                height = pictureBox.Image.Height;

            Bitmap newBmp = new Bitmap(width, height);
            pictureBox.DrawToBitmap(newBmp, new Rectangle(new Point(0, 0), newBmp.Size));
            newBmp.Save(fileName);
            newBmp.Dispose();
            ShowCrossHair = showCross;
            pictureBox.Invalidate();
        }

        public new void Load(String fileName)
        {
            XmlDocument newDocument = new XmlDocument();
            newDocument.Load(fileName);
            XmlNode rootNode = newDocument.SelectSingleNode("Project");
            XmlNode objectNode = rootNode.SelectSingleNode("Objects");
            GeoObjects.Clear();
            foreach (XmlNode objNode in objectNode.ChildNodes)
            {
                GeoObject newObject = CreateObjectFromObjectNode(objNode, newDocument);
                GeoObjects.Add(newObject);
                newObject.Parent = this;
            }

            XmlNode bgImageNode = rootNode.SelectSingleNode("BGImage");
            Image = bgImageNode.Attributes["Path"].Value;
        }

        private void toolStripButtonRuler_Click(object sender, EventArgs e)
        {
            toolStripButtonCalibrate.Checked = false;
            toolStripButtonRuler.Checked = !toolStripButtonRuler.Checked;
            if (!toolStripButtonRuler.Checked)
            {
                EditMode = CADEditMode.View;
            }
        }

        public void FitImgInPicBox()
        {
            try
            {
                float widthFactor = (float)this.pictureBox.Width / pictureBox.Image.Width;
                float heightFactor = (float)this.pictureBox.Height / pictureBox.Image.Height;
                if (widthFactor < heightFactor)
                {
                    this.pictureBox.CurrentZoom = widthFactor;
                }
                else
                {
                    this.pictureBox.CurrentZoom = heightFactor;
                }
                Invalidate(true);
            }
            catch { }
        }


        /// <summary>
        /// Sorgt dafür, dass der übergebene Bereich sichtbar ist
        /// </summary>
        /// <param name="leftPoint">Linke obere Ecke des Bereichs</param>
        /// <param name="rightPoint">Rechte untere Ecke des Bereichs</param>
        public void FocusArea(Vector2D leftPoint, Vector2D rightPoint)
        {
            Vector2D leftPointTranslated = leftPoint * Zoom;// *TranslationScaleMatrix;
            Vector2D rightPointTranslated = rightPoint * Zoom;// *TranslationScaleMatrix;

            Size scrollbarSize = pictureBox.Size - pictureBox.ClientSize;
            int x = pictureBox.HorizontalScroll.Value;
            int y = pictureBox.VerticalScroll.Value;
            if (rightPointTranslated.X > (pictureBox.Width + pictureBox.HorizontalScroll.Value - scrollbarSize.Width)) //läuft nach rechts raus
            {
                x = x + (int)(rightPointTranslated.X - (pictureBox.HorizontalScroll.Value + pictureBox.Width) + scrollbarSize.Width * 2);
            }
            else if (leftPointTranslated.X < (pictureBox.HorizontalScroll.Value)) //läuft nach links raus
            {
                x = x - (int)((pictureBox.HorizontalScroll.Value - leftPointTranslated.X) + scrollbarSize.Width * 2);
            }

            if (rightPointTranslated.Y > (pictureBox.Height + pictureBox.VerticalScroll.Value - scrollbarSize.Height)) //läuft nach unten raus
            {
                y = y + (int)(rightPointTranslated.Y - (pictureBox.VerticalScroll.Value + pictureBox.Height) + scrollbarSize.Height * 2);
            }
            else if (leftPointTranslated.Y < (pictureBox.VerticalScroll.Value)) //läuft nach oben raus
            {
                y = y - (int)((pictureBox.VerticalScroll.Value - leftPointTranslated.Y) + scrollbarSize.Height * 2);
            }

            pictureBox.AutoScrollPosition = new Point(x, y);
            UpdateTranslation();
            pictureBox.Invalidate(true);



            //Vector2D leftPointTranslated = leftPoint * TranslationScaleMatrix;
            //Vector2D rightPointTranslated = rightPoint * TranslationScaleMatrix;

            //Size scrollbarSize = pictureBox.Size - pictureBox.ClientSize;
            //int x =  pictureBox.AutoScrollPosition.X;
            //int y = pictureBox.AutoScrollPosition.Y;


            //if (rightPointTranslated.X > (pictureBox.Width + pictureBox.AutoScrollPosition.X)) //läuft nach rechts raus
            //{
            //    x = x + (int)((rightPointTranslated.X - (pictureBox.AutoScrollPosition.X + pictureBox.Width)) + scrollbarSize.Width);
            //}
            //else if (leftPointTranslated.X < (pictureBox.AutoScrollPosition.X)) //läuft nach links raus
            //{
            //    x = x - (int)((pictureBox.AutoScrollPosition.X - leftPointTranslated.X) - scrollbarSize.Width);
            //}

            //if (rightPointTranslated.Y > (pictureBox.Height + pictureBox.AutoScrollPosition.Y)) //läuft nach unten raus
            //{
            //    y = y + (int)((rightPointTranslated.Y - (pictureBox.AutoScrollPosition.Y + pictureBox.Height)) + scrollbarSize.Height);
            //}
            //else if (leftPointTranslated.Y < (pictureBox.AutoScrollPosition.Y)) //läuft nach oben raus
            //{
            //    y = y - (int)((pictureBox.AutoScrollPosition.Y - leftPointTranslated.Y) - scrollbarSize.Height);
            //}

            //pictureBox.AutoScrollPosition = new Point(x, y);
            //UpdateTranslation();
            //pictureBox.Invalidate(true);

        }

        private void UpdateLayersInContextMenus()
        {
            contextMenuStripMovePoint.Items.Clear();
            contextMenuStripMovePoint.Items.Add(new ToolStripMenuItem(@"Objekt clonen", null, objektClonenToolStripMenuItem_Click));
            contextMenuStripMovePoint.Items.Add(new ToolStripMenuItem(@"Objekt löschen", null, objektLöschenToolStripMenuItem_Click));

            foreach (int key in LayerColorTable.Keys)
            {
                ToolStripMenuItem tItem = new ToolStripMenuItem("Layer " + key.ToString());
                tItem.Tag = key;
                tItem.BackColor = LayerColorTable[key].Color == Color.Black ? Color.White : LayerColorTable[key].Color;
                tItem.Click += new EventHandler(LayerMenuItem_Click);
                contextMenuStripMovePoint.Items.Add(tItem);
            }
        }

        void LayerMenuItem_Click(object sender, EventArgs e)
        {
            if(selectedObject != null)
            {
                selectedObject.Layer = (int) (sender as ToolStripMenuItem).Tag;
                EditMode = CADEditMode.View;
                pictureBox.Invalidate(true);               
            }
            
        }


        private void toolStripButtonBGImage_Click(object sender, EventArgs e)
        {
            if (openImageDialog.ShowDialog() == DialogResult.OK && openImageDialog.FileName != String.Empty)
            {
                if (openImageDialog.FileName != this.Image)
                    geoObjects.Clear();
                this.Image = openImageDialog.FileName;
                toolStripStatusLabelFileName.Text = new System.IO.FileInfo(openImageDialog.FileName).Name;
            }
        }

        private void toolStripTextBoxMeters_TextChanged(object sender, EventArgs e)
        {
            //Parser für Kalibrierung
            //int factor;

            //if (int.TryParse(toolStripTextBoxMeters.Text, out factor) && factor >= 0)
            //{

            //    toolStripTextBoxMeters.Text = factor.ToString();
            //}
            //else
            //{
            //    toolStripTextBoxMeters.Text = "10";//((int)(pictureBox.CurrentZoom * 100)).ToString();
            //}
        }


        private void EnableCamSettingsButton()
        {
            toolStripButtonCamSettings.Enabled = true;
        }

        private void DisableCamSettingsButton()
        {
            toolStripButtonCamSettings.Enabled = false;
        }

        private void GrabFrame()
        {
            pictureBox.Image = grabber.Grab();
        }

        private void livecamWorker_DoWork(object sender, DoWorkEventArgs e)
        {

            this.Invoke(new System.Windows.Forms.MethodInvoker(this.EnableCamSettingsButton));

            while (!livecamWorker.CancellationPending)
            {
                this.Invoke(new System.Windows.Forms.MethodInvoker(this.GrabFrame));
                System.Threading.Thread.Sleep(50);
            }
            grabber.StopDevice();
            grabber.Dispose();
            this.Invoke(new System.Windows.Forms.MethodInvoker(this.DisableCamSettingsButton));
        }

        private void toolStripButtonLiveImage_Click(object sender, EventArgs e)
        {
            if (toolStripButtonLiveImage.Checked) //Livemodus gestartet
            {
                if (VLib.Grabber.CountGrabberDevices() > 1)
                {
                    //Auswahldialog, wenn mehr als eine Kamera angeschlossen ist
                    CamForm cform = new CamForm();
                    List<String> camList = new List<String>();
                    for (int i = 0; i < VLib.Grabber.CountGrabberDevices(); i++)
                    {
                        camList.Add(VLib.Grabber.GetDeviceName(i));
                    }
                    cform.Cameras = camList;
                    cform.StartPosition = FormStartPosition.CenterParent;
                    if (cform.ShowDialog() == DialogResult.Cancel) //Abbruch durch Benutzer
                    {
                        toolStripButtonLiveImage.Checked = false;
                        return;
                    }
                    if (cform.CamIndex > -1)
                    {
                        grabber = new VLib.Grabber(cform.CamIndex, cform.Res.Width, cform.Res.Height);
                    }
                    else
                    {
                        toolStripButtonLiveImage.Checked = false;
                        return;
                    }

                }
                else
                {
                    grabber = new VLib.Grabber();
                }
                grabber.SetAutoReconnectOnFreeze(true, 10);
                if (!livecamWorker.IsBusy)
                {
                    livecamWorker.RunWorkerAsync();
                }
            }
            else
            {
                livecamWorker.CancelAsync();
            }
        }

        private void toolStripButtonCamSettings_Click(object sender, EventArgs e)
        {
            grabber.ShowSettings();
        }

        private void toolStripButtonWriteMeasured_Click(object sender, EventArgs e)
        {
            SaveMeasure(this, new MeasureEventArgs(measureStartTranslated, measureEndTranslated, measureDistance, pxCount));
        }

        private void toolStripButtonUndo_Click(object sender, EventArgs e)
        {
            if (toolStripButtonManualCellCount.Checked)
            {
                if (manualCellCountPoints.Count > 0)
                {
                    manualCellCountPoints.RemoveAt(manualCellCountPoints.Count - 1);
                    toolStripButtonUndo.Enabled = manualCellCountPoints.Count > 0;
                }
                this.Invalidate(true);
                return;
            }
            GeoObjects = undoList[undoList.Count - 1];
                if (Undone != null)
                {
                    Undone(this, new EventArgs());
                }
                undoList.RemoveAt(undoList.Count - 1);
                toolStripButtonUndo.Enabled = undoList.Count > 0;
                this.Invalidate(true);
            
        }

        private void toolStripButtonClearObjects_Click(object sender, EventArgs e)
        {
            GeoObjects.Clear();
            this.Invalidate();
        }

        private void CADControl_Resize(object sender, EventArgs e)
        {
            UpdateTranslation();
            this.Invalidate(true);
        }

        private void toolStripButtoncalibrate_Click(object sender, EventArgs e)
        {
            toolStripButtonRuler.Checked = false;
            toolStripButtonCalibrate.Checked = !toolStripButtonCalibrate.Checked;
            if (!toolStripButtonCalibrate.Checked)
            {
                EditMode = CADEditMode.View;
            }
        }

        private void toolStripButtonLayerSettings_Click(object sender, EventArgs e)
        {
            LayerPropertiesDialog dlg = new LayerPropertiesDialog();
            dlg.OverrideColors = UseLayerColors;
            dlg.LayerColorTable = LayerColorTable;
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                LayerColorTable = dlg.LayerColorTable;
                UseLayerColors = dlg.OverrideColors;

                String[] colorLines = new String[LayerColorTable.Count + 1];
                colorLines[0] = UseLayerColors.ToString();
                int i = 1; //wegen erste zeile schon geschrieben
                foreach (var layerColor in LayerColorTable)
                {
                    colorLines[i++] = layerColor.Key.ToString() + ":" + layerColor.Value.Color.ToArgb() + ":" + layerColor.Value.Width.ToString();
                }
                try
                {
                    File.WriteAllLines("layer_colors", colorLines);
                }
                catch
                {
                    //keine schreibrechte
                }
                UpdateLayersInContextMenus();
            }
            pictureBox.Invalidate(true);

        }

        private void pictureBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Control && selectedObject != null)
            {
                switch (e.KeyCode)
                {
                    case Keys.D0:
                        selectedObject.Layer = 0;
                        pictureBox.Invalidate(true);
                        break;
                    case Keys.D1:
                        selectedObject.Layer = 1;
                        pictureBox.Invalidate(true);
                        break;
                    case Keys.D2:
                        selectedObject.Layer = 2;
                        pictureBox.Invalidate(true);
                        break;
                    case Keys.D3:
                        selectedObject.Layer = 3;
                        pictureBox.Invalidate(true);
                        break;
                    case Keys.D4:
                        selectedObject.Layer = 4;
                        pictureBox.Invalidate(true);
                        break;
                    case Keys.D5:
                        selectedObject.Layer = 5;
                        pictureBox.Invalidate(true);
                        break;
                    case Keys.D6:
                        selectedObject.Layer = 6;
                        pictureBox.Invalidate(true);
                        break;
                    case Keys.D7:
                        selectedObject.Layer = 7;
                        pictureBox.Invalidate(true);
                        break;
                    case Keys.D8:
                        selectedObject.Layer = 8;
                        pictureBox.Invalidate(true);
                        break;
                    case Keys.D9:
                        selectedObject.Layer = 9;
                        pictureBox.Invalidate(true);
                        break;
                    default:
                        break;
                }
            }
        }

        private void toolStripButtonManualCellCount_Click(object sender, EventArgs e)
        {

            foreach (var obj in toolStrip.Items)
            {
                (obj as ToolStripItem).Enabled = !toolStripButtonManualCellCount.Checked;
                
            }
            toolStripButtonManualCellCount.Enabled = true;
            toolStripButtonHideObjects.Enabled = true;
            toolStripSplitButtonColorType.Enabled = true;
            toolStripButtonIndividualColor.Enabled = true;
            toolStripButtonUndo.Enabled = manualCellCountPoints.Count > 0;
            Invalidate(true);
        }

        private void toolStripButtonHideObjects_Click(object sender, EventArgs e)
        {
            this.Invalidate(true);
        }

        private void complementColorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            toolStripButtonIndividualColor.Visible = false;
            complementColorToolStripMenuItem.Checked = true;
            individualColorToolStripMenuItem.Checked = false;
        }

        private void individualColorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            toolStripButtonIndividualColor.Visible = true;
            individualColorToolStripMenuItem.Checked = true;
            complementColorToolStripMenuItem.Checked = false;
        }

        private void toolStripButtonIndividualColor_Click(object sender, EventArgs e)
        {
            if (colorDialog.ShowDialog() == DialogResult.OK)
            {
                countColor = colorDialog.Color;
            }
        }

        /*
        private void toolStripButtonManualCellCount_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                //trackBarRadius.SetBounds(0, 0, 0, 0);
                //trackBarRadius.Location = this.PointToClient(Cursor.Position);
                //trackBarRadius.Visible = !trackBarRadius.Visible;
            }
        }
        */
       
    }


    #region Hilfsklassen
    /// <summary>
    /// Erweiterungsmethode zum Clonen der GeoObject-Liste
    /// </summary>
    public static class ExtensionClass
    {
        //Erweiterungs-Methode für den hier angegebenen Typ nach this -> List<GeoObject>
        public static List<GeoObject> Clone(this List<GeoObject> list)
        {
            List<GeoObject> newList = new List<GeoObject>();

            foreach (GeoObject item in list)
            {
                newList.Add(item.Clone());
            }
            return newList;
        }

        public enum Units { nm, µm, mm, m }
        public struct DoubleUnit
        {
            public double Value;
            public Units Unit;
        }

        public static DoubleUnit ToDoubleUnit(this double value)
        {
            double val = value;
            DoubleUnit dVal = new DoubleUnit();
            dVal.Unit = Units.m;
            while (val < 1)
            {
                val *= 1000;
                dVal.Unit--;
                dVal.Value = Math.Round(val, 3);
                if (dVal.Unit == 0)
                {
                    break;
                }
            }
            return dVal;
        }
    }

    public class GeoObjectEventArgs : EventArgs
    {
        public GeoObject Obj
        {
            set;
            get;
        }
    }

    #endregion

}
